import {
  computed,
  defineComponent,
  ExtractPropTypes,
  nextTick,
  ref,
  Teleport,
  watchEffect,
} from "vue";
import { Button, Modal } from "ant-design-vue";
import { withInstall } from "ant-design-vue/es/_util/type";
import { modalProps } from "ant-design-vue/es/modal/Modal";
import {
  FullscreenOutlined,
  FullscreenExitOutlined,
  CloseOutlined,
} from "@ant-design/icons-vue";
import { CustomRenderFalse } from "./typings";
import {
  registerModalBorderDraw,
  registerModalDrag,
  resetModalCenterY,
  resetModalMinWH,
  resetModalWH,
} from "./utils";
import { getSlotVNode } from "./utils/getSlot";
import "./ProModal.css";

export const proModalProps = {
  ...modalProps(),
  /**点击蒙层是否允许关闭 */
  maskClosable: {
    type: Boolean,
    default: false,
  },
  /**宽度， 默认`520` */
  width: {
    type: Number,
    default: 520,
  },
  /**最小宽度， 默认`364` */
  minWidth: {
    type: Number,
    default: 364,
  },
  /**最小高度， 默认`256` */
  minHeight: {
    type: Number,
    default: 256,
  },
  /**打开始终按默认宽度水平居中展示,偏离顶部 `top:100px` */
  centerY: {
    type: Boolean,
    default: false,
  },
  /**按住标题拖动模态对话框 */
  drag: {
    type: Boolean,
    default: false,
  },
  /**模态对话框边界拉伸 */
  borderDraw: {
    type: Boolean,
    default: false,
  },
  /**是否显示右上角的全屏按钮 */
  fullscreen: {
    type: Boolean,
    default: false,
  },
  /**强制全屏显示 */
  forceFullscreen: {
    type: Boolean,
    default: false,
  },
};

export type ProModalProps = Partial<ExtractPropTypes<typeof proModalProps>>;

const proModal = defineComponent({
  name: "ProModal",
  inheritAttrs: true,
  props: proModalProps,
  emits: ["update:open", "update:fullscreen", "rect"],
  setup(props, { emit, slots, attrs }) {
    const baseClassName = "ant-pro-modal";
    /**组件初始化监听事件标记，防止重复注册 */
    const initialized = ref<boolean>(false);
    /**组件模态框宽度属性标记 */
    const wdithMark = ref<string | number>(
      Math.max(props.width, props.minWidth)
    );
    /**模态框外层对象DOM，一定存在 */
    const proModalRef = ref<HTMLElement>(
      document.body.querySelector(baseClassName)!
    );
    /**全屏模式 */
    const fullscreenModel = ref(props.forceFullscreen);
    /**全屏按钮事件 */
    function onFullscreen() {
      fullscreenModel.value = !fullscreenModel.value;
      emit("update:fullscreen", fullscreenModel.value);
      // 回调事件，传递当前模态框的尺寸信息
      nextTick(() => {
        const proModalEl = proModalRef.value;
        const modalEl = proModalEl.querySelector<HTMLDivElement>(".ant-modal");
        if (!modalEl) return;
        const rect = modalEl.getBoundingClientRect();
        emit("rect", rect.toJSON());
      });
    }
    /**关闭按钮事件 */
    function onClose(e: MouseEvent) {
      emit("update:open", false);
      props.onCancel && props.onCancel(e);
    }

    /**没有自定义关闭图标时进行插槽渲染 */
    const defaultCloseIconRender = () => (
      <div
        class={`${baseClassName}-closeIcon__custom`}
        onClick={(e) => {
          // 阻止事件的默认行为和停止事件的传播，防止原关闭按钮事件触发
          e.preventDefault();
          e.stopPropagation();
        }}
      >
        {props.fullscreen && (
          <Button
            size="small"
            type="text"
            icon={
              fullscreenModel.value ? (
                <FullscreenExitOutlined />
              ) : (
                <FullscreenOutlined />
              )
            }
            onClick={onFullscreen}
          ></Button>
        )}
        <Button
          size="small"
          type="text"
          icon={<CloseOutlined />}
          onClick={onClose}
        ></Button>
      </div>
    );

    watchEffect(() => {
      if (!props.open) return;
      // 关闭时销毁 Modal 里的子元素，需要打开时重新初始化事件
      if (props.destroyOnClose) {
        initialized.value = false;
      }
      nextTick(() => {
        const proModalEl = proModalRef.value;
        const modalWrapEl =
          proModalEl.querySelector<HTMLDivElement>(".ant-modal-wrap");
        const modalEl = proModalEl.querySelector<HTMLDivElement>(".ant-modal");

        if (!modalWrapEl || !modalEl) return;

        // 模态框居中处理
        if (fullscreenModel.value && props.fullscreen) {
          const leftWidth = modalWrapEl.offsetWidth - props.width;
          modalEl.style.top = "100px";
          modalEl.style.left = `${leftWidth / 2}px`;
        } else {
          resetModalCenterY(modalEl, props.centerY);
        }

        // 模态框最大宽高处理
        resetModalWH(modalWrapEl, modalEl);

        if (initialized.value) return;
        // 开启模态框拖拽
        if (props.drag) {
          const headerEl =
            modalEl.querySelector<HTMLDivElement>(".ant-modal-header");
          if (headerEl) {
            registerModalDrag(
              modalEl,
              headerEl,
              () => props.centered || fullscreenModel.value,
              () => {
                // 回调事件，传递当前模态框的尺寸信息
                const rect = modalEl.getBoundingClientRect();
                emit("rect", rect.toJSON());
              }
            );
          }
        }
        // 开启模态框边界拉伸
        if (props.borderDraw) {
          resetModalMinWH(modalEl, props.minWidth, props.minHeight);
          registerModalBorderDraw(
            modalWrapEl,
            modalEl,
            props.minWidth,
            props.minHeight,
            () => props.centered || fullscreenModel.value,
            () => {
              // 回调事件，传递当前模态框的尺寸信息
              const rect = modalEl.getBoundingClientRect();
              wdithMark.value = rect.width;
              emit("rect", rect.toJSON());
            }
          );
        }
        initialized.value = true;
      });
    });

    return () => {
      /**标题 */
      const titleRender = getSlotVNode<CustomRenderFalse>(
        slots,
        props,
        "title"
      );
      /**底部内容 */
      const footerRender = getSlotVNode<CustomRenderFalse>(
        slots,
        props,
        "footer"
      );
      /**确认按钮文字 */
      const okTextRender = getSlotVNode<CustomRenderFalse>(
        slots,
        props,
        "okText"
      );
      /**取消按钮文字 */
      const cancelTextRender = getSlotVNode<CustomRenderFalse>(
        slots,
        props,
        "cancelText"
      );
      /**自定义关闭图标 */
      const closeIconRender = getSlotVNode<CustomRenderFalse>(
        slots,
        props,
        "closeIcon"
      );

      return (
        <Teleport to={props.getContainer || "body"}>
          <div
            ref={proModalRef}
            class={{
              [baseClassName]: true,
              [`${baseClassName}-fullscreen`]: fullscreenModel.value,
              [`${baseClassName}-closeIcon`]: !closeIconRender,
            }}
          >
            <Modal
              {...props}
              {...attrs}
              width={wdithMark.value}
              getContainer={() => proModalRef.value}
              title={titleRender}
              footer={footerRender}
              okText={okTextRender}
              cancelText={cancelTextRender}
              closeIcon={closeIconRender ?? defaultCloseIconRender()}
            >
              {slots.default && slots.default()}
            </Modal>
          </div>
        </Teleport>
      );
    };
  },
});

export default withInstall(proModal);
